﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using KTOP.Core.Extensions;

namespace KTOP.Core.Netlists.Parsing
{
    // just a XML model

    public class NetlistParser
    {
        private static netlist DeserializeModel(Stream stream)
        {
            var xml = new XmlSerializer(typeof(netlist));
            return (netlist)xml.Deserialize(stream);
        }

        private static Net ParseNet(string net, int netId, Module[] modules)
        {
            var pins = net.SplitAndTrim(',')
                .Where(p => !string.IsNullOrEmpty(p))
                .Select(p =>
                            {
                                var net1 = net;
                                var parts = p.Split('/');
                                var moduleId = int.Parse(parts[0]);
                                var pinId = int.Parse(parts[1]);

                                if (moduleId > modules.Length || moduleId < 1)
                                    throw new Exception("Module " + moduleId +
                                                        " is not exist");

                                if (pinId > modules[moduleId - 1].PinCount || pinId < 0)
                                    throw new Exception("Pin " + pinId + " not exist.");

                                return modules[moduleId - 1][pinId - 1];
                            })
                .ToArray();

            return new Net(netId, pins);
        }

        public Netlist Parse(string filename)
        {
            var model = DeserializeModel(File.OpenRead(filename));
            var nets = model.nets.Replace("\r\n", "\n")
                .Replace('\r', '\n')
                .SplitAndTrim('\n')
                .Where(n => !string.IsNullOrEmpty(n))
                .ToArray();

            var modules = Enumerable.Range(0, model.modules)
                .Select(n => Module.Create(n, model.pins))
                .ToArray();

            return new Netlist(modules, nets.Select((n, i) => ParseNet(n, i + 1, modules)).ToArray());
        }
    }
}
